home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  15.6 KB  |  641 lines

  1. /* 
  2.  * mem.c--
  3.  *
  4.  *    Memory management for Jaquith archive package.
  5.  *
  6.  * Copyright 1992 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/mem.c,v 1.0 91/01/07 18:02:37 mottsmth Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <stdio.h>
  21. #include "jaquith.h"
  22.  
  23. typedef struct nodedef {
  24.     char *name;
  25.     int line;
  26.     int size;
  27.     int freeLink;
  28.     char *ptr;
  29.     unsigned char flags;
  30. } NODE;
  31.  
  32. typedef struct tabdef {
  33.     int inuse;
  34.     int cnt;
  35.     NODE *tab;
  36. } TAB;
  37.  
  38. #define CHUNK 1000
  39. #define BORDER "################"
  40. #define BORDERSIZE 16
  41. #define MAXNAMELEN 20
  42. #define PTRFIELD 1
  43. #define NAMEFIELD 2
  44. #define SIZEFIELD 3
  45. #define FREE 1
  46. #define RETURNED 2
  47. #define BITPATTERN '@'
  48. #define NIL -1
  49.  
  50. #define REAL_ALLOC(x) malloc(x)
  51. #define REAL_FREE(x) free(x)
  52.  
  53. static int maxBlkSize = 0x10000;
  54. static int maxFreeSpace = 0;
  55. static int traceFlags = 0;
  56. static FILE *outStream = stderr;
  57. static int freeHead = NIL;
  58. static int freeTail = NIL;
  59.  
  60. int traceInit = 0;
  61.  
  62. static TAB blks = { 0, 0, (NODE *)NULL};
  63. static int outCnt = 0;
  64. static int outSize = 0;
  65. static int totAlloc = 0;
  66. static int totFree = 0;
  67. static int curFree = 0;
  68.  
  69. static void CheckBlk   _ARGS_ ((NODE *nodePtr, int count));
  70. static void PrintNodes _ARGS_ ((char *ownerName, NODE **nodeList, int count));
  71. static void SortNodes  _ARGS_ ((NODE **nodeList, int count, int field));
  72. static void Die        _ARGS_ (());
  73.  
  74.  
  75. /*
  76.  *----------------------------------------------------------------------
  77.  *
  78.  * Mem_Alloc--
  79.  *
  80.  *    Safe memory allocator. This gives us a place to localize
  81.  * and trace memory use, if it should become necessary.
  82.  *
  83.  * Results:
  84.  *    Ptr to block of specified size or NULL;
  85.  *
  86.  * Side effects:
  87.  *    Allocates heap space.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91.  
  92. char *
  93. Mem_Alloc(callerName, callerLine, callerSize)
  94.     char *callerName;         /* calling procedure's name */
  95.     int callerLine;           /* line no in caller's source */
  96.     int callerSize;           /* requested block size */
  97. {
  98.     int i;
  99.     NODE *newTab;
  100.     NODE *nodePtr;
  101.     char *blkPtr;
  102.     int blkSize;
  103.  
  104.     blkSize = callerSize + 2*BORDERSIZE;
  105.  
  106.     if (!(traceFlags & TRACEMEM)) {
  107.     blkPtr = (char *)REAL_ALLOC(blkSize);
  108.     strncpy(blkPtr, BORDER, BORDERSIZE);
  109.     blkPtr += BORDERSIZE;
  110.     strncpy(blkPtr+callerSize, BORDER, BORDERSIZE);
  111.     return(blkPtr);
  112.     }
  113.  
  114.     if (callerSize == 0) {
  115.     fprintf(outStream,"*** Mem_Alloc (%s:%d) size is zero.\n",
  116.         callerName, callerLine);
  117.     } else if (callerSize < 0) {
  118.     fprintf(outStream,"*** Mem_Alloc (%s:%d) size is <= 0: %08x\n",
  119.         callerName, callerLine, callerSize);
  120.     Die();
  121.     } else if (callerSize > maxBlkSize) {
  122.     fprintf(outStream,"*** Mem_Alloc (%s:%d) size exceeds limit (%08x): %08x\n",
  123.         callerName, callerLine, maxBlkSize, callerSize);
  124.     Die();
  125.     }
  126.  
  127.     if (blks.inuse >= blks.cnt) {
  128.     fprintf(outStream, "*** Mem_Alloc (%s:%d) alloc %d (0x%x) byte table\n",
  129.         callerName, callerLine,
  130.         (blks.cnt+CHUNK)*sizeof(NODE),    (blks.cnt+CHUNK)*sizeof(NODE));
  131.     newTab = (NODE *)REAL_ALLOC( (blks.cnt+CHUNK)*sizeof(NODE) );
  132.     if (newTab == (NODE *)NULL) {
  133.         fprintf(outStream, "*** Mem_Alloc (%s:%d) couldn't get private table space\n",
  134.         callerName, callerLine);
  135.         Die();
  136.     }
  137.     for (i=0; i<blks.cnt; i++) {
  138.         newTab[i] = blks.tab[i];
  139.     }
  140.     blks.cnt += CHUNK;
  141.     if (blks.tab != (NODE *)NULL) {
  142.         REAL_FREE(blks.tab);
  143.     }
  144.     blks.tab = newTab;
  145.     }
  146.  
  147.     totAlloc++;
  148.     outSize += callerSize;
  149.     outCnt++;
  150.     nodePtr = blks.tab+blks.inuse;
  151.     nodePtr->name = callerName;
  152.     nodePtr->line = callerLine;
  153.     nodePtr->size = callerSize;
  154.     nodePtr->flags = 0;
  155.     blkPtr = (char *)REAL_ALLOC(blkSize);
  156.     strncpy(blkPtr, BORDER, BORDERSIZE);
  157.     blkPtr += BORDERSIZE;
  158.     nodePtr->ptr = blkPtr;
  159.     strncpy(blkPtr+callerSize, BORDER, BORDERSIZE);
  160.     blks.inuse++;
  161.  
  162.     if (traceFlags & TRACECALLS) {
  163.     fprintf(outStream,"Mem_Alloc (%s:%d) ptr=0x%08x; size=0x%08x\n",
  164.         callerName, callerLine, blkPtr, callerSize);
  165.     }
  166.  
  167.     if (traceFlags & CHECKALLBLKS) {
  168.     CheckBlk(blks.tab, blks.inuse);
  169.     }
  170.  
  171.     if (traceFlags & TRACESTATS) {
  172.     Mem_Report(callerName,callerLine,callerName,SORTBYADDR);
  173.     }
  174.  
  175.     return(blkPtr);
  176.  
  177. } /* Mem_Alloc */
  178.  
  179.  
  180. /*
  181.  *----------------------------------------------------------------------
  182.  *
  183.  * Mem_Free--
  184.  *
  185.  *    Safe memory allocator. This gives us a place to localize
  186.  * and trace memory use, if it should become necessary.
  187.  *
  188.  * Results:
  189.  *    Ptr to block of specified size or NULL;
  190.  *
  191.  * Side effects:
  192.  *    Allocates heap space.
  193.  *
  194.  *----------------------------------------------------------------------
  195.  */
  196.  
  197. int
  198. Mem_Free(callerName, callerLine, callerPtr)
  199.     char *callerName;         /* calling procedure's name */
  200.     int callerLine;           /* line no in caller's source */
  201.     char *callerPtr;          /* block to be released */
  202. {
  203.     int blkNum;
  204.     int i;
  205.     char *blkPtr;
  206.     NODE *nodePtr;
  207.  
  208.     blkPtr = callerPtr - BORDERSIZE;
  209.  
  210.     if (!(traceFlags & TRACEMEM)) {
  211.     REAL_FREE(blkPtr);
  212.     return 0;
  213.     }
  214.  
  215.     for (blkNum=blks.inuse-1,nodePtr= &blks.tab[blks.inuse-1];
  216.      blkNum>=0; blkNum--,nodePtr--) {
  217.     if (nodePtr->ptr == callerPtr) {
  218.         break;
  219.     }
  220.     }
  221.  
  222.     if (traceFlags & TRACECALLS) {
  223.     fprintf(outStream,"Mem_Free  (%s:%d) ptr=0x%08x size=0x%08x\n",
  224.         callerName, callerLine, callerPtr, 
  225.         (blkNum < 0) ? -1 : nodePtr->size);
  226.     }
  227.  
  228.     if (blkNum < 0) {
  229.     if (!(traceFlags & IGNOREMISSINGBLK)) {
  230.         fprintf(outStream, "*** Mem_Free  (%s:%d) didn't find block ptr=0x%08x.\n",
  231.             callerName, callerLine, callerPtr);
  232.     }
  233.     if (!(traceFlags & IGNOREMISSINGBLK+WARNMISSINGBLK)) {
  234.         Die();
  235.     }
  236.     return(0);
  237.     }
  238.  
  239.     if (nodePtr->flags & FREE) {
  240.     fprintf(outStream,"*** Mem_Free  (%s:%d) block 0x%08x alloc'd by %s already free.\n",
  241.         callerName, callerLine, callerPtr, nodePtr->name);
  242.     }
  243.  
  244.     if (!(traceFlags & CHECKALLBLKS)) {
  245.     CheckBlk(nodePtr, 1);
  246.     }
  247.  
  248.     for (i=0; i<nodePtr->size; i++) {
  249.     callerPtr[i] = BITPATTERN;
  250.     }
  251.  
  252.     totFree++;
  253.     outCnt--;
  254.     outSize -= nodePtr->size;
  255.     curFree += nodePtr->size;
  256.     nodePtr->flags |= FREE;
  257.     nodePtr->freeLink = NIL;
  258.  
  259.     if (traceFlags & CHECKALLBLKS) {
  260.     CheckBlk(blks.tab, blks.inuse);
  261.     }
  262.  
  263.     if (traceFlags & TRACESTATS) {
  264.     Mem_Report(callerName,callerLine,callerName,SORTBYADDR);
  265.     }
  266.  
  267.     /* enqueue block on free chain */
  268.     if (freeHead == NIL) {
  269.     freeHead = blkNum;
  270.     } else {
  271.     nodePtr = &blks.tab[freeTail];
  272.     nodePtr->freeLink = blkNum;
  273.     }
  274.     freeTail = blkNum;
  275.  
  276.     while ((curFree > maxFreeSpace) && (freeHead != NIL)) {
  277.     /* dequeue first block */
  278.     nodePtr = &blks.tab[freeHead];
  279.     CheckBlk(nodePtr, 1);
  280.         freeHead = nodePtr->freeLink;    
  281.     curFree -= nodePtr->size;
  282.     nodePtr->flags |= RETURNED;
  283.     REAL_FREE(nodePtr->ptr-BORDERSIZE);
  284.     }
  285.  
  286.     return(0);
  287.  
  288. } /* Mem_Free */
  289.  
  290.  
  291. /*
  292.  *----------------------------------------------------------------------
  293.  *
  294.  * Mem_Report--
  295.  *
  296.  *    Report results of tracing
  297.  *
  298.  * Results:
  299.  *    None.
  300.  *
  301.  * Side effects:
  302.  *    None.
  303.  *
  304.  *----------------------------------------------------------------------
  305.  */
  306.  
  307. void
  308. Mem_Report(callerName, callerLine, ownerName, reportFlags)
  309.     char *callerName;         /* calling procedure's name */
  310.     int callerLine;           /* line no in caller's source */
  311.     char *ownerName;          /* blocker owner's name */
  312.     int reportFlags;          /* output flags */
  313. {
  314.     int i,j;
  315.     int nodeCnt = 0;
  316.     NODE *nodePtr;
  317.     NODE **arr;
  318.     
  319.     if (!(traceFlags & TRACEMEM)) {
  320.     return;
  321.     }
  322.  
  323.     for (i=0, nodePtr=blks.tab; i<blks.inuse; i++,nodePtr++) {
  324.     if (((!(nodePtr->flags & FREE)) || (reportFlags & REPORTALLBLKS)) &&
  325.         ((strcmp(ownerName, ALLROUTINES) == 0) ||
  326.          (strcmp(nodePtr->name,ownerName) == 0))) {
  327.         nodeCnt++;
  328.     }
  329.     }
  330.  
  331.     arr = (NODE **)REAL_ALLOC(nodeCnt*sizeof(NODE *));
  332.     if (arr == NULL) {
  333.     fprintf(outStream,"Mem_Report: couldn't get private table space.\n");
  334.     Die();
  335.     }
  336.  
  337.     for (i=0, j=0,nodePtr=blks.tab; i<blks.inuse; i++,nodePtr++) {
  338.     if (((!(nodePtr->flags & FREE)) || (reportFlags & REPORTALLBLKS)) &&
  339.         ((strcmp(ownerName, ALLROUTINES) == 0) ||
  340.          (strcmp(nodePtr->name,ownerName) == 0))) {
  341.         arr[j++] = nodePtr;
  342.     }
  343.     }
  344.  
  345.     fprintf(outStream,"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");    
  346.  
  347.     if (reportFlags & SORTBYREQ) {
  348.     fprintf(outStream, "Mem_Report (%s:%d) blks for %s, ordered by request:\n",
  349.         callerName, callerLine, ownerName);
  350.     PrintNodes(ownerName, arr, nodeCnt);
  351.     }
  352.     if (reportFlags & SORTBYADDR) {
  353.     fprintf(outStream, "Mem_Report (%s:%d) blks for %s, ordered by address:\n",
  354.         callerName, callerLine, ownerName);
  355.     SortNodes(arr, nodeCnt, PTRFIELD);
  356.     PrintNodes(ownerName, arr, nodeCnt);
  357.     }
  358.     if (reportFlags & SORTBYOWNER) {
  359.     fprintf(outStream, "Mem_Report (%s:%d) blks for %s, ordered by owner:\n",
  360.         callerName, callerLine, ownerName);
  361.     SortNodes(arr, nodeCnt, NAMEFIELD);
  362.     PrintNodes(ownerName, arr, nodeCnt);
  363.     }
  364.     if (reportFlags & SORTBYSIZE) {
  365.     fprintf(outStream, "Mem_Report (%s:%d) blks for %s, ordered by size:\n",
  366.         callerName, callerLine, ownerName);
  367.     SortNodes(arr, nodeCnt, SIZEFIELD);
  368.     PrintNodes(ownerName, arr, nodeCnt);
  369.     }
  370.     REAL_FREE(arr);
  371.  
  372.     if (strcmp(ownerName, ALLROUTINES) != 0) {
  373.     fprintf(outStream, "In use by all routines: %d (0x%x) blocks; %d (0x%x) bytes.\n",
  374.         outCnt, outCnt, outSize, outSize);
  375.     }
  376.  
  377.     fprintf(outStream,"Call counts: Mem_Alloc %d; Mem_Free %d\n",
  378.         totAlloc, totFree);
  379.     fprintf(outStream,"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  380.     fflush(outStream);
  381.  
  382. } /* Mem_Report */
  383.  
  384.  
  385. /*
  386.  *----------------------------------------------------------------------
  387.  *
  388.  * Mem_Report--
  389.  *
  390.  *    Report results of tracing
  391.  *
  392.  * Results:
  393.  *    None.
  394.  *
  395.  * Side effects:
  396.  *    None.
  397.  *
  398.  *----------------------------------------------------------------------
  399.  */
  400.  
  401. static void
  402. PrintNodes(ownerName, nodeList, nodeCnt)
  403.     char *ownerName;          /* block owner's name */
  404.     NODE **nodeList;          /* list of nodes to be printed */
  405.     int  nodeCnt;             /* number of nodes */
  406. {
  407.     int i,odd;
  408.     int localSize = 0; 
  409.     int localCnt = 0;
  410.     NODE *nodePtr1;
  411.     NODE *nodePtr2;
  412.     int half;
  413.     char buf1[1024];
  414.     char buf2[1024];
  415.     char free1;
  416.     char free2;
  417.  
  418.     half = nodeCnt >> 1;
  419.  
  420.     if (2*half == nodeCnt) {
  421.     odd = 0;
  422.     } else if (2*half == nodeCnt-1) {
  423.     odd = 1;
  424.     }
  425.  
  426.     if (nodeCnt > 0) {
  427.     fprintf(outStream, "    owner               size      ptr        owner             size      ptr\n");
  428.     }
  429.  
  430.     for (i=0; i<half; i+=2) {
  431.     nodePtr1 = nodeList[i];
  432.     nodePtr2 = nodeList[i+i];
  433.     free1 = ' ';
  434.     free2 = ' ';
  435.     if (!(nodePtr1->flags & FREE)) {
  436.         localSize += nodePtr1->size;
  437.         localCnt++;
  438.         free1 = '!';
  439.     }
  440.     if (!(nodePtr2->flags & FREE)) {
  441.         localSize += nodePtr2->size;
  442.         localCnt++;
  443.         free2 = '!';
  444.     }
  445.     strcpy(buf1, nodePtr1->name);
  446.     sprintf(buf1+strlen(buf1),":%d",nodePtr1->line);
  447.     strcpy(buf2, nodePtr2->name);
  448.     sprintf(buf2+strlen(buf2),":%d",nodePtr2->line);
  449.     fprintf(outStream, "%-*s %c%08x %08x  %-*s %c%08x %08x\n",
  450.         MAXNAMELEN, buf1, free1, nodePtr1->size, nodePtr1->ptr,
  451.         MAXNAMELEN, buf2, free2, nodePtr2->size, nodePtr2->ptr);
  452.     } 
  453.  
  454.     if (odd == 1) {
  455.     nodePtr1 = nodeList[nodeCnt-1];
  456.     strcpy(buf1, nodePtr1->name);
  457.     sprintf(buf1+strlen(buf1),":%d",nodePtr1->line);
  458.     free1 = ' ';
  459.     if (!(nodePtr1->flags & FREE)) {
  460.         localSize += nodePtr1->size;
  461.         localCnt++;
  462.         free1 = '!';
  463.     }
  464.     fprintf(outStream, "%-*s %c%08x %08x\n",
  465.         MAXNAMELEN, buf1, free1, nodePtr1->size, nodePtr1->ptr);
  466.     }
  467.     fprintf(outStream, "In use by %s - %d (0x%x) blocks; %d (0x%x) bytes.\n\n",
  468.         ownerName, localCnt, localCnt, localSize, localSize);
  469.  
  470. } /* PrintNodes */
  471.  
  472.  
  473.  
  474. /*
  475.  *----------------------------------------------------------------------
  476.  *
  477.  * Mem_Control --
  478.  *
  479.  *    Control diagnostic memory stuff
  480.  *
  481.  * Results:
  482.  *    None.
  483.  *
  484.  * Side effects:
  485.  *    Sets tracing flags.
  486.  *
  487.  *----------------------------------------------------------------------
  488.  */
  489.  
  490. void
  491. Mem_Control(callerBlkSize, callerStream, callerFlags, callerFree)
  492.     int callerBlkSize;        /* Maximum block size */
  493.     FILE *callerStream;       /* Diagnostic output stream */
  494.     int callerFlags;          /* tracing flags. see mem.h */
  495.     int callerFree;           /* max freed block space before returning to REALFREE */
  496.  
  497. {
  498.     if (callerBlkSize >= 0) {
  499.     maxBlkSize = callerBlkSize;
  500.     }
  501.  
  502.     if (callerStream != (FILE *)NULL) {
  503.     outStream = callerStream;
  504.     }
  505.  
  506.     if ((traceFlags & IGNOREMISSINGBLK) &&
  507.     (traceFlags & WARNMISSINGBLK)) {
  508.     fprintf(stderr,"conflicting trace flags.\n");
  509.     exit(0);
  510.     }
  511.  
  512.     maxFreeSpace = callerFree;
  513.     traceFlags = callerFlags;
  514.  
  515.     if ((!(traceFlags & TRACEMEM)) && (blks.tab != NULL)) {
  516.     free(blks.tab);
  517.     blks.tab = (NODE *)NULL;
  518.     blks.cnt = 0;
  519.     outStream = stderr;
  520.     }
  521.     
  522.     traceInit = 1;
  523.     
  524. } /* Mem_Control */
  525.  
  526.  
  527. /*
  528.  *----------------------------------------------------------------------
  529.  *
  530.  * SortNodes
  531.  *
  532.  *    Quickie sort routine
  533.  *
  534.  * Results:
  535.  *    None.
  536.  *
  537.  * Side effects:
  538.  *    None.
  539.  *
  540.  *----------------------------------------------------------------------
  541.  */
  542.  
  543. static void
  544. SortNodes(nodeList, nodeCnt, field)
  545.     NODE **nodeList;          /* list of nodes */
  546.     int nodeCnt;              /* number of nodes */
  547.     int field;                /* field to sort on */
  548. {
  549.     int i,j,gap;
  550.     NODE *temp;
  551.  
  552.     for (gap=nodeCnt/2; gap>0; gap /= 2) {
  553.     for (i=gap; i<nodeCnt; i++) {
  554.         if (field == PTRFIELD) {
  555.         for (j=i-gap;
  556.              j>=0 && nodeList[j]->ptr>nodeList[j+gap]->ptr;
  557.              j-=gap) {
  558.             temp = nodeList[j];
  559.             nodeList[j] = nodeList[j+gap];
  560.             nodeList[j+gap] = temp;
  561.         }
  562.         } else if (field == NAMEFIELD) {
  563.         for (j=i-gap;
  564.              j>=0 && (strcmp(nodeList[j]->name,nodeList[j+gap]->name) >0);
  565.              j-=gap) {
  566.             temp = nodeList[j];
  567.             nodeList[j] = nodeList[j+gap];
  568.             nodeList[j+gap] = temp;
  569.         }
  570.         } else if (field == SIZEFIELD) {
  571.         for (j=i-gap;
  572.              j>=0 && nodeList[j]->size>nodeList[j+gap]->size;
  573.              j-=gap) {
  574.             temp = nodeList[j];
  575.             nodeList[j] = nodeList[j+gap];
  576.             nodeList[j+gap] = temp;
  577.         }
  578.         }
  579.     }
  580.     }
  581.  
  582. } /* SortNodes */
  583.  
  584.  
  585. /*
  586.  *----------------------------------------------------------------------
  587.  *
  588.  * CheckBlk--
  589.  *
  590.  *    Verify that border hasn't been overwritten.
  591.  *      For free blocks verify that no new bits have appeared.
  592.  *
  593.  * Results:
  594.  *    None.
  595.  *
  596.  * Side effects:
  597.  *    None.
  598.  *
  599.  *----------------------------------------------------------------------
  600.  */
  601.  
  602. static void
  603. CheckBlk(nodePtr, count)
  604.     NODE *nodePtr;            /* block list */
  605.     int count;                /* number of blocks */
  606. {
  607.     int i;
  608.  
  609.     while (count-- > 0) {
  610.     if (!(nodePtr->flags & FREE) &&
  611.         ((bcmp(nodePtr->ptr-BORDERSIZE,BORDER,BORDERSIZE) != 0) || 
  612.         (bcmp(nodePtr->ptr+nodePtr->size,BORDER,BORDERSIZE) != 0))) {
  613.         fprintf(outStream, "*** CheckBlk: owner=%s; line=%d, ptr=0x%08x; size=0x%08x: border overwritten!\n",
  614.         nodePtr->name, nodePtr->line, nodePtr->ptr, nodePtr->size);
  615.         Die();
  616.     }
  617.     if ((nodePtr->flags & FREE) && (!(nodePtr->flags & RETURNED))) {
  618.         for (i=0; i<nodePtr->size; i++) {
  619.         if (nodePtr->ptr[i] != BITPATTERN) {
  620.             fprintf(outStream, "*** CheckBlk: owner=%s; line=%d, ptr=0x%08x; size=0x%08x: freed block modified!\n",
  621.             nodePtr->name, nodePtr->line, nodePtr->ptr, nodePtr->size);
  622.             Die();
  623.         }
  624.         }
  625.     }
  626.     nodePtr++;
  627.     }
  628.  
  629. } /* CheckBlk */
  630.  
  631.  
  632. static void
  633. Die()
  634. {
  635.     if (outStream != NULL) {
  636.     fflush(outStream);
  637.     }
  638.     fprintf("%s", 0); /* double ptr whammy */
  639.     exit(-1); /* just in case */
  640. }
  641.